home *** CD-ROM | disk | FTP | other *** search
- ; Iterator example.
- ;
- ; Roughly corresponds to the example in Ghezzi & Jazayeri's
- ; "Programming Language Concepts" text.
- ;
- ; Randall Hyde
- ;
- ;
- ; This program demonstrates an implementation of:
- ;
- ; l := 0;
- ; foreach i in range(1,3) do
- ; foreach j in iter2() do
- ; writeln(i, ',', j, ',', l):
- ;
- ;
- ; iterator range(start,stop):integer;
- ; begin
- ;
- ; while start <= stop do begin
- ;
- ; yield start;
- ; start := start+1;
- ; end;
- ; end;
- ;
- ; iterator iter2:integer;
- ; var k:integer;
- ; begin
- ;
- ; foreach k in iter3 do
- ; yield k;
- ; end;
- ;
- ; iterator iter3:integer;
- ; begin
- ;
- ; l := l + 1;
- ; yield 1;
- ; l := l + 1;
- ; yield 2;
- ; l := l + 1;
- ; yield 0;
- ; end;
- ;
- ;
- ; This code will print:
- ;
- ; 1, 1, 1
- ; 1, 2, 2
- ; 1, 0, 3
- ; 2, 1, 4
- ; 2, 2, 5
- ; 2, 0, 6
- ; 3, 1, 7
- ; 3, 2, 8
- ; 3, 0, 9
-
-
-
-
- .xlist
- include stdlib.a
- includelib stdlib.lib
- .list
-
- .286 ;Allow extra adrs modes.
-
-
-
- dseg segment para stack 'data'
-
-
-
- ; Put the stack in the data segment so we can use the small memory model
- ; to simplify addressing:
-
- stk byte 1024 dup ('stack')
- EndStk word 0
-
- dseg ends
-
-
-
-
-
- cseg segment para public 'code'
- assume cs:cseg, ds:dseg, ss:dseg
-
-
-
-
- ; Here's the structure of a resume frame. Note that this structure isn't
- ; actually used in this code. It is only provided to show you what data
- ; is sitting on the stack when Yield builds a resume frame.
-
- RsmFrm struct
- ResumeAdrs word ?
- IteratorLink word ?
- RsmFrm ends
-
-
-
-
- ; The following macro builds a resume frame and the returns to the caller
- ; of an iterator. It assumes that the iterator and whoever called the
- ; iterator have the standard activation record defined above and that we
- ; are building the standard resume frame described above.
- ;
- ; This code wipes out the DX register. Whoever calls the iterator cannot
- ; count on DX being preserved, likewise, the iterator cannot count on DX
- ; being preserved across a yield. Presumably, the iterator returns its
- ; value in AX.
-
- ActRec struct
- DynamicLink word ? ;Saved BP value.
- YieldAdrs word ? ;Return Adrs for proc.
- StaticLink word ? ;Static link for proc.
- ActRec ends
-
- AR equ [bp].ActRec
-
- Yield macro
- mov dx, AR.YieldAdrs ;Place to yield back to.
- push bp ;Save Iterator link
- mov bp, AR.DynamicLink ;Get ptr to caller's A.R.
- call dx ;Push resume address and rtn.
- pop bp ;Restore ptr to our A. R.
- endm
-
-
-
-
-
-
- ; Range(start, stop) - Yields start..stop and then fails.
-
- ; The following structure defines the activation record for Range:
-
- rngAR struct
- DynamicLink word ? ;Saved BP value.
- YieldAdrs word ? ;Return Adrs for proc.
- StaticLink word ? ;Static link for proc.
- FailAdrs word ? ;Go here when we fail
- Stop word ? ;Stop parameter
- Start word ? ;Start parameter
-
- rngAR ends
-
-
- rAR equ [bp].rngAR
-
-
- Range proc
- push bp
- mov bp, sp
-
- ; While start <= stop, yield start:
-
- WhlStartLEStop: mov ax, rAR.Start ;Also puts return value
- cmp ax, rAR.Stop ; in AX.
- jnle RangeFail
-
- yield
-
- inc rAR.Start
- jmp WhlStartLEStop
-
- RangeFail: pop bp ;Restore Dynamic Link.
- add sp, 4 ;Skip ret adrs and S.L.
- ret 4 ;Return through fail address.
- Range endp
-
-
-
-
- ; Iter2- Just calls iter3() and returns whatever value it generates.
- ;
- ; Note: Since iter2 and iter3 are at the same lex level, the static link
- ; passed to iter3 must be the same as the static link passed to iter2.
- ; This is why the "push [bp]" instruction appears below (as opposed to the
- ; "push bp" instruction which appears in the calls to Range and iter2).
- ; Keep in mind, Range and iter2 are only called from main and bp contains
- ; the static link at that point. This is not true when iter2 calls iter3.
-
- iter2 proc
- push bp
- mov bp, sp
-
- push offset i3Fail ;Failure address.
- push [bp] ;Static link is link to main.
- call iter3
- yield ;Return value returned by iter3
- ret ;Resume Iter3.
-
- i3Fail: pop bp ;Restore Dynamic Link.
- add sp, 4 ;Skip return address & S.L.
- ret ;Return through fail address.
- iter2 endp
-
-
-
- ; Iter3() simply yields the values 1, 2, and 0:
-
- iter3 proc
- push bp
- mov bp, sp
-
- mov bx, AR.StaticLink ;Point BX at main's AR.
- inc word ptr [bx-6] ;Increment L in main.
- mov ax, 1
- yield
-
- mov bx, AR.StaticLink
- inc word ptr [bx-6]
- mov ax, 2
- yield
- mov bx, AR.StaticLink
- inc word ptr [bx-6]
- mov ax, 0
- yield
-
- pop bp ;Restore Dynamic Link.
- add sp, 4 ;Skip return address & S.L.
- ret ;Return through fail address.
- iter3 endp
-
-
-
-
-
-
- ; Main's local variables are allocated on the stack in order to justify
- ; the use of static links.
-
- i equ [bp-2]
- j equ [bp-4]
- l equ [bp-6]
-
-
- Main proc
- mov ax, dseg
- mov ds, ax
- mov es, ax
- mov ss, ax
- mov sp, offset EndStk
-
- ; Allocate storage for i, j, and l on the stack:
-
- mov bp, sp
- sub sp, 6
-
- meminit
-
- mov word ptr l, 0 ;Initialize l.
-
- ; foreach i in range(1,3) do:
-
- push 1 ;Parameters.
- push 3
- push offset iFail ;Failure address.
- push bp ;Static link points at our AR.
- call Range
-
- ; Yield from range comes here. The label is for your benefit.
-
- RangeYield: mov i, ax ;Save away loop control value.
-
- ; foreach j in iter2 do:
-
- push offset jfail ;Failure address.
- push bp ;Static link points at our AR.
- call iter2
-
-
- ; Yield from iter2 comes here:
-
- iter2Yield: mov j, ax
-
- mov ax, i
- puti
- print
- byte ", ",0
- mov ax, j
- puti
- print
- byte ", ",0
- mov ax, l
- puti
- putcr
-
- ; Restart iter2:
-
- ret ;Resume iterator.
-
-
- ; Restart Range down here:
-
- jFail: ret ;Resume iterator.
-
- ; All Done!
-
- iFail: print
- byte cr,lf,"All Done!",cr,lf,0
-
-
-
-
- Quit: ExitPgm ;DOS macro to quit program.
- Main endp
-
- cseg ends
-
-
-
- ; zzzzzzseg must be the last segment that gets loaded into memory!
- ; This is where the heap begins.
-
- zzzzzzseg segment para public 'zzzzzz'
- LastBytes db 16 dup (?)
- zzzzzzseg ends
- end Main
-